﻿using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Security.Cryptography;
using System.Text;
using System.Threading.Tasks;

namespace GXRTBTC.PublicClassLibrary.Util
{
    public static class RsaUtil
    {
        //20230906生成
        //固化密钥，以后系统使用此密钥，不再更改
        public const string publicKey = "<RSAKeyValue><Modulus>qFjygkYpb1P2nNxIIkB5kom1LQ87IA9+HmTeEKQJnmivFDiB72vrouTfOq8mO+mDgxY1CIOCjFmBRhQdP4VTc1/QFvlYvyDch9T0gZjttUqscIrYTdlC1puUVVmZDxpQnuQsGlf2zWicPYtveV1tmHcgebAMIZshumfmzDHgRs0=</Modulus><Exponent>AQAB</Exponent></RSAKeyValue>";
        public const string privateKey = "<RSAKeyValue><Modulus>qFjygkYpb1P2nNxIIkB5kom1LQ87IA9+HmTeEKQJnmivFDiB72vrouTfOq8mO+mDgxY1CIOCjFmBRhQdP4VTc1/QFvlYvyDch9T0gZjttUqscIrYTdlC1puUVVmZDxpQnuQsGlf2zWicPYtveV1tmHcgebAMIZshumfmzDHgRs0=</Modulus><Exponent>AQAB</Exponent><P>0UqixioRnZtOQZi9T3uzspyhcCd8sonowXuO5EQ4IHiEBXxiBRrK7ri4/JnxwDyyub5C+Czh6uV1vNAY6SwjJw==</P><Q>zesR6xs06YbXFJ4VYVzy+2B22fMrUuXL8jE/m5AD1ZRLHNzgocDQ7aIWWx9CfHOKLRMv8+s3TsRwLrkdQn0u6w==</Q><DP>JT7iDuAHuIOd/qB++DksdpnXRQ1R7LgMOvqRKGBXmLe5zvweuYfWG3u2OAXxduOWbuXEJ0RdhB8Hv+1MsZpQOw==</DP><DQ>EbvI00KIkAP4yeHDXZsvoc5w7dwvQvhfVABBxhfk/KPExDuRbNy6IXzwB/DtPOKGZ9NbMdpz7Oil8KAokO1O+Q==</DQ><InverseQ>XOItqGe/MCh2TFi31KBzE+UZWYuu/O/kJSnlN02ZbtgNwuJfKWYvox3Ofi29IfNs3X3E6GQ5TDUgM38ucfthNQ==</InverseQ><D>Y3GPZ0b8yOeHQOeasKj3Z4ly/XgGzAx6yod46cmMaQebjE1I694LJoEeIDNAWZm59uBSWYIdxrxEcdoF4PTn8sT8LVw4LEBa6j3F3KD5d1U0+uPbYy56hIfRq0XOT48Xg40R+BmFX8JjEC7512HcmU7ob62m5KB2wYzpV2q6Yd0=</D></RSAKeyValue>";

        private static void Test()
        {
            //！！！结果显示太长，请自行运行！！！
            string content = "10.170.1.235:7001,10.170.1.66:7005,10.170.1.235:7002,10.170.1.66:7006,password=gxrtbtc,SyncTimeout=20000";
            content = "张三";

            //获取公钥和私钥，每次生成的都不一样
            KeyModel encryptDecrypt = RsaEncrypt.GetKeyPair();

            //以后系统使用此密钥，不再更改
            //encryptDecrypt.PublicKey = "<RSAKeyValue><Modulus>qFjygkYpb1P2nNxIIkB5kom1LQ87IA9+HmTeEKQJnmivFDiB72vrouTfOq8mO+mDgxY1CIOCjFmBRhQdP4VTc1/QFvlYvyDch9T0gZjttUqscIrYTdlC1puUVVmZDxpQnuQsGlf2zWicPYtveV1tmHcgebAMIZshumfmzDHgRs0=</Modulus><Exponent>AQAB</Exponent></RSAKeyValue>";
            //encryptDecrypt.PrivateKey = "<RSAKeyValue><Modulus>qFjygkYpb1P2nNxIIkB5kom1LQ87IA9+HmTeEKQJnmivFDiB72vrouTfOq8mO+mDgxY1CIOCjFmBRhQdP4VTc1/QFvlYvyDch9T0gZjttUqscIrYTdlC1puUVVmZDxpQnuQsGlf2zWicPYtveV1tmHcgebAMIZshumfmzDHgRs0=</Modulus><Exponent>AQAB</Exponent><P>0UqixioRnZtOQZi9T3uzspyhcCd8sonowXuO5EQ4IHiEBXxiBRrK7ri4/JnxwDyyub5C+Czh6uV1vNAY6SwjJw==</P><Q>zesR6xs06YbXFJ4VYVzy+2B22fMrUuXL8jE/m5AD1ZRLHNzgocDQ7aIWWx9CfHOKLRMv8+s3TsRwLrkdQn0u6w==</Q><DP>JT7iDuAHuIOd/qB++DksdpnXRQ1R7LgMOvqRKGBXmLe5zvweuYfWG3u2OAXxduOWbuXEJ0RdhB8Hv+1MsZpQOw==</DP><DQ>EbvI00KIkAP4yeHDXZsvoc5w7dwvQvhfVABBxhfk/KPExDuRbNy6IXzwB/DtPOKGZ9NbMdpz7Oil8KAokO1O+Q==</DQ><InverseQ>XOItqGe/MCh2TFi31KBzE+UZWYuu/O/kJSnlN02ZbtgNwuJfKWYvox3Ofi29IfNs3X3E6GQ5TDUgM38ucfthNQ==</InverseQ><D>Y3GPZ0b8yOeHQOeasKj3Z4ly/XgGzAx6yod46cmMaQebjE1I694LJoEeIDNAWZm59uBSWYIdxrxEcdoF4PTn8sT8LVw4LEBa6j3F3KD5d1U0+uPbYy56hIfRq0XOT48Xg40R+BmFX8JjEC7512HcmU7ob62m5KB2wYzpV2q6Yd0=</D></RSAKeyValue>";
            
            Console.WriteLine($"私钥：\n{encryptDecrypt.PrivateKey}");
            Console.WriteLine($"公钥：\n{encryptDecrypt.PublicKey}");

            Console.WriteLine($"原文:\n{content}");

            //------------------------------私钥--------------------------------------
            //加密 -- 私钥能加密的原因是私钥包含公钥
            //string encryptResultPrivate = RsaEncrypt.Encrypt("张三", encryptDecrypt.PrivateKey);
            string encryptResultPrivate = RsaEncrypt.EncryptFree(content, encryptDecrypt.PrivateKey);
            Console.WriteLine($"密文:\n{encryptResultPrivate}");
            //解密
            //Console.WriteLine($"解密：{RsaEncrypt.Decrypt(encryptResultPrivate, encryptDecrypt.PrivateKey)}");
            Console.WriteLine($"解密：{RsaEncrypt.DecryptFree(encryptResultPrivate, encryptDecrypt.PrivateKey)}");

            //------------------------------公钥--------------------------------------
            //加密
            //string encryptResultPublic = RsaEncrypt.Encrypt("张三", encryptDecrypt.PublicKey);
            string encryptResultPublic = RsaEncrypt.EncryptFree(content, encryptDecrypt.PublicKey);
            Console.WriteLine($"密文:\n{encryptResultPublic}");
            //解密
            //Console.WriteLine($"解密：{RsaEncrypt.Decrypt(encryptResultPublic, encryptDecrypt.PrivateKey)}");
            Console.WriteLine($"解密：{RsaEncrypt.DecryptFree(encryptResultPublic, encryptDecrypt.PrivateKey)}");

            //------------------------------签名--------------------------------------
            //生成签名
            Console.WriteLine($"生成签名");
            string autograph = RsaEncrypt.SignData("生成签名的原文", encryptDecrypt.PrivateKey);
            Console.WriteLine($"签名:{autograph}");

            //验证签名
            Console.WriteLine($"验证签名:{RsaEncrypt.VerifyData("生成签名的原文", autograph, encryptDecrypt.PublicKey)}");
            Console.WriteLine($"验证签名原文改动:{RsaEncrypt.VerifyData("生成签名的原文改动", autograph, encryptDecrypt.PublicKey)}");
        }
    }

    /// <summary>
    /// 密钥类
    /// </summary>
    public class KeyModel
    {
        /// <summary>
        /// 公有Key---加密key
        /// </summary>
        public string PublicKey { get; set; }

        /// <summary>
        /// 私有Key--可以加密也可以加密
        /// </summary>
        public string PrivateKey { get; set; }

        /// <summary>
        /// 构造函数
        /// </summary>
        /// <param name="publicKey">共有key</param>
        /// <param name="privateKey">私有key</param>
        public KeyModel(string publicKey, string privateKey)
        {
            this.PublicKey = publicKey;
            this.PrivateKey = privateKey;
        }
    }

    /// <summary>
    /// Rsa加密 -- 非对称式
    /// </summary>
    public static class RsaEncrypt
    {
        /// <summary>
        /// 获取公钥/私钥
        /// 每次生成的公钥和私钥都不一样
        /// </summary>
        /// <returns>Encrypt   Decrypt</returns>
        public static KeyModel GetKeyPair()
        {
            RSACryptoServiceProvider RSA = new RSACryptoServiceProvider();

            //包括专用参数： 如果为true，则包含公钥和私钥RSA密钥；false，仅包括公众钥匙 
            string publicKey = RSA.ToXmlString(false); //生成的是公开的解密key
            string privateKey = RSA.ToXmlString(true); //生成的是私有的既可以加密也可以解密的key
            return new KeyModel(publicKey, privateKey);
        }

        /// <summary>
        /// RSA加密，对应Decrypt
        /// </summary>
        /// <param name="encryptText">待加密文本</param>
        /// <param name="encryptKey">加密key</param>
        /// <returns>加密后字符</returns>
        public static string Encrypt(string encryptText, string encryptKey = RsaUtil.publicKey)
        {
            RSACryptoServiceProvider rsa = new RSACryptoServiceProvider();
            rsa.FromXmlString(encryptKey);

            UnicodeEncoding ByteConverter = new UnicodeEncoding();
            //内容转成Unicode编码
            byte[] DataToEncrypt = ByteConverter.GetBytes(encryptText);
            //生成Rsa码
            byte[] resultBytes = rsa.Encrypt(DataToEncrypt, false);

            //字节转字符串
            return Convert.ToBase64String(resultBytes);
        }

        /// <summary>
        /// 加密，无限制长度
        /// 和DecryptFree对应
        /// </summary>
        /// <param name="rawInput"></param>
        /// <param name="publicKey"></param>
        /// <returns></returns>
        /// <exception cref="ArgumentException"></exception>
        public static string EncryptFree(string encryptText, string encryptKey = RsaUtil.publicKey)
        {
            if (string.IsNullOrEmpty(encryptText))
            {
                return string.Empty;
            }

            if (string.IsNullOrWhiteSpace(encryptKey))
            {
                throw new ArgumentException("Invalid Public Key");
            }

            using (var rsaProvider = new RSACryptoServiceProvider())
            {
                var inputBytes = Encoding.UTF8.GetBytes(encryptText);//有含义的字符串转化为字节流
                rsaProvider.FromXmlString(encryptKey);//载入公钥
                int bufferSize = (rsaProvider.KeySize / 8) - 11;//单块最大长度
                var buffer = new byte[bufferSize];
                using (MemoryStream inputStream = new MemoryStream(inputBytes),
                     outputStream = new MemoryStream())
                {
                    while (true)
                    {
                        //分段加密
                        int readSize = inputStream.Read(buffer, 0, bufferSize);
                        if (readSize <= 0)
                        {
                            break;
                        }

                        var temp = new byte[readSize];
                        Array.Copy(buffer, 0, temp, 0, readSize);
                        var encryptedBytes = rsaProvider.Encrypt(temp, false);
                        outputStream.Write(encryptedBytes, 0, encryptedBytes.Length);
                    }
                    return Convert.ToBase64String(outputStream.ToArray());//转化为字节流方便传输
                }
            }
        }

        /// <summary>
        /// RSA解密，对应Encrypt
        /// </summary>
        /// <param name="decryptText">待解密文本</param>
        /// <param name="decryptKey">解密key</param>
        /// <returns>解密后字符</returns>
        public static string Decrypt(string decryptText, string decryptKey = RsaUtil.privateKey)
        {
            //字符转字节
            byte[] dataToDecrypt = Convert.FromBase64String(decryptText);

            RSACryptoServiceProvider RSA = new RSACryptoServiceProvider();
            RSA.FromXmlString(decryptKey);
            //解码
            byte[] resultBytes = RSA.Decrypt(dataToDecrypt, false);

            UnicodeEncoding ByteConverter = new UnicodeEncoding();
            //根据Unicode转化成字符串
            return ByteConverter.GetString(resultBytes);
        }


        /// <summary>
        /// 解密，无限制长度
        /// 和EncryptFree对应
        /// </summary>
        /// <param name="encryptedInput"></param>
        /// <param name="privateKey"></param>
        /// <returns></returns>
        /// <exception cref="ArgumentException"></exception>
        public static string DecryptFree(string decryptText, string decryptKey = RsaUtil.privateKey)
        {
            if (string.IsNullOrEmpty(decryptText))
            {
                return string.Empty;
            }

            if (string.IsNullOrWhiteSpace(decryptKey))
            {
                throw new ArgumentException("Invalid Private Key");
            }

            using (var rsaProvider = new RSACryptoServiceProvider())
            {
                var inputBytes = Convert.FromBase64String(decryptText);
                rsaProvider.FromXmlString(decryptKey);
                int bufferSize = rsaProvider.KeySize / 8;
                var buffer = new byte[bufferSize];
                using (MemoryStream inputStream = new MemoryStream(inputBytes),
                     outputStream = new MemoryStream())
                {
                    while (true)
                    {
                        int readSize = inputStream.Read(buffer, 0, bufferSize);
                        if (readSize <= 0)
                        {
                            break;
                        }

                        var temp = new byte[readSize];
                        Array.Copy(buffer, 0, temp, 0, readSize);
                        var rawBytes = rsaProvider.Decrypt(temp, false);
                        outputStream.Write(rawBytes, 0, rawBytes.Length);
                    }
                    return Encoding.UTF8.GetString(outputStream.ToArray());
                }
            }
        }

        /// <summary>
        /// 生成签名
        /// </summary>
        /// <param name="content">原文</param>
        /// <param name="privatekey">私钥</param>
        /// <returns>加密后字符</returns>
        public static string SignData(string content, string privatekey)
        {
            //字符转字节
            byte[] messagebytes = Encoding.UTF8.GetBytes(content);

            RSACryptoServiceProvider oRSA3 = new RSACryptoServiceProvider();
            oRSA3.FromXmlString(privatekey);

            //生成签名
            byte[] AOutput = oRSA3.SignData(messagebytes, "SHA1");
            //字节转字符
            return Convert.ToBase64String(AOutput);
        }

        /// <summary>
        /// 验证签名
        /// </summary>
        /// <param name="content">原文</param>
        /// <param name="autograph">签名</param>
        /// <param name="publickey">共有key</param>
        /// <returns>
        ///     true -- 验证成功
        ///     false -- 验证失败
        /// </returns>
        public static bool VerifyData(string content, string autograph, string publickey)
        {
            //字符转字节
            byte[] messagebytes = Encoding.UTF8.GetBytes(content);
            byte[] messageAutographbytes = Convert.FromBase64String(autograph);

            RSACryptoServiceProvider RSA = new RSACryptoServiceProvider();
            RSA.FromXmlString(publickey);

            //验证 content 和 autograph 是否相同
            bool bVerify = RSA.VerifyData(messagebytes, "SHA1", messageAutographbytes);
            return bVerify;
        }

        /// <summary>
        /// 生成公钥私钥，同时完成加密
        /// </summary>
        /// <param name="content"></param>
        /// <param name="encryptKey">加密key</param>
        /// <param name="decryptKey">解密key</param>
        /// <returns>加密后结果</returns>
        private static string Encrypt(string content, out string publicKey, out string privateKey)
        {
            RSACryptoServiceProvider rsaProvider = new RSACryptoServiceProvider();
            publicKey = rsaProvider.ToXmlString(false);
            privateKey = rsaProvider.ToXmlString(true);

            UnicodeEncoding ByteConverter = new UnicodeEncoding();
            byte[] DataToEncrypt = ByteConverter.GetBytes(content);
            byte[] resultBytes = rsaProvider.Encrypt(DataToEncrypt, false);
            return Convert.ToBase64String(resultBytes);
        }
    }
}
